//package com.tianji.promotion.service.impl;
//
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.tianji.common.exceptions.BadRequestException;
//import com.tianji.common.exceptions.BizIllegalException;
//import com.tianji.common.utils.StringUtils;
//import com.tianji.common.utils.UserContext;
//import com.tianji.promotion.domain.po.Coupon;
//import com.tianji.promotion.domain.po.ExchangeCode;
//import com.tianji.promotion.domain.po.UserCoupon;
//import com.tianji.promotion.enums.CouponStatus;
//import com.tianji.promotion.enums.ExchangeCodeStatus;
//import com.tianji.promotion.mapper.CouponMapper;
//import com.tianji.promotion.mapper.UserCouponMapper;
//import com.tianji.promotion.service.IExchangeCodeService;
//import com.tianji.promotion.service.IUserCouponService;
//import com.tianji.promotion.utils.CodeUtil;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.redisson.api.RLock;
//import org.redisson.api.RedissonClient;
//import org.springframework.aop.framework.AopContext;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.time.LocalDateTime;
//
///**
// * <p>
// * 用户领取优惠券的记录，是真正使用的优惠券信息 服务实现类
// * </p>
// *
// * @author zzj
// * @since 2024-05-23
// */
//@Slf4j
//@Service
//@RequiredArgsConstructor
//public class UserCouponRedissonServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon> implements IUserCouponService {
//
//    private final CouponMapper couponMapper;
//    private final IExchangeCodeService exchangeCodeService;
//    private final RedissonClient redissonClient;
//
//    /**
//     * @description: 领取优惠券
//     * @params: [id]
//     * @return:
//     * @author: ajie
//     * @date: 2024/5/24 15:27
//     */
//    @Override
//    public void receiveCoupon(Long id) {
//        //校验id查询优惠券状态 做相关校验
//        if (id == null){
//            throw new BadRequestException("非法参数");
//        }
//        Coupon coupon = couponMapper.selectById(id);
//        if (coupon == null){
//            throw new BadRequestException("优惠券不存在");
//        }
//        if (coupon.getStatus() != CouponStatus.ISSUING){
//            throw new BadRequestException("该优惠券不是正在发放中");
//        }
//        LocalDateTime now = LocalDateTime.now();
//        if (now.isBefore(coupon.getIssueBeginTime()) || now.isAfter(coupon.getIssueEndTime())){
//            throw new BadRequestException("该优惠券已过期或未发放");
//        }
//        if (coupon.getTotalNum() <= 0 || coupon.getIssueNum() >= coupon.getTotalNum()){
//            throw new BadRequestException("该优惠券库存不足");
//        }
//        Long userId = UserContext.getUser();
//        /*//获取当前用户 对该优惠券 已领数量 user_coupon 条件userId couponId
//        Integer count = this.lambdaQuery()
//                .eq(UserCoupon::getUserId, userId)
//                .eq(UserCoupon::getCouponId, id)
//                .count();
//        if (count != null && count>=coupon.getUserLimit()){
//            throw new BadRequestException("已达到领取上限");
//        }
//        //优惠券的已发放数量+1
////        coupon.setIssueNum(coupon.getIssueNum() + 1);
////        couponMapper.updateById(coupon);
//        couponMapper.incrIssueNum(id);//采用这种方式 后期考虑并发控制 后期仍需修改
//
//        //生成用户券
//        saveUserCoupon(userId,coupon);*/
////        checkAndCreateUserCoupon(userId, coupon,null);
//
////        synchronized (userId.toString().intern()){
////            checkAndCreateUserCoupon(userId, coupon,null);
////        }
//
////        synchronized (userId.toString().intern()){
////            //从aop上下文中 获取当前类的代理对象
////            IUserCouponService userCouponServiceProxy = (IUserCouponService) AopContext.currentProxy();
//////            checkAndCreateUserCoupon(userId, coupon,null);//这种方法是调用原对象的方法
////            userCouponServiceProxy.checkAndCreateUserCoupon(userId, coupon,null);//这种方法调用代理对象的方法，方法是有事务处理的
////        }
//
//        //通过redisson实现分布式锁
//        String key = "lock:coupon:uid";
//        RLock lock = redissonClient.getLock(key);//获取锁对象
//        try {
//            boolean isLock = lock.tryLock();//没有参数，看门狗机制会生效，默认失效时间是30秒
//            if (!isLock){
//                throw new  BizIllegalException("操作太频繁了");
//            }
//            //从aop上下文中 获取当前类的代理对象
//            IUserCouponService userCouponServiceProxy = (IUserCouponService) AopContext.currentProxy();
////            checkAndCreateUserCoupon(userId, coupon,null);//这种方法是调用原对象的方法
//            userCouponServiceProxy.checkAndCreateUserCoupon(userId, coupon,null);//这种方法调用代理对象的方法，方法是有事务处理的
//        }finally {
//            lock.unlock();
//        }
//
//    }
//
//    @Override
//    @Transactional
//    public void exchangeCoupon(String code) {
//        //校验code是否为空
//        if (StringUtils.isBlank(code)){
//            throw new BadRequestException("非法参数");
//        }
//        //解析兑换码得到自增id
//        long serialNum = CodeUtil.parseCode(code);//自增id
//        log.debug("自增id：{}",serialNum);
//        //判断兑换码是否已兑换 采用redis的bitmap结构 setbit key offset 1 如果方法返回为true代表兑换码已兑换
//        boolean result = exchangeCodeService.updateExchangeCodeMark(serialNum,true);
//        if (result){
//            //说明兑换码已经被兑换
//            throw new BizIllegalException("兑换码已经被使用");
//        }
//        try {
//            //判断兑换码是否存在 根据自增id查询 主键查询
//            ExchangeCode exchangeCode = exchangeCodeService.getById(serialNum);
//            if (exchangeCode == null){
//                throw new BizIllegalException("兑换码不存在");
//            }
//            //判断是否过期
//            LocalDateTime now = LocalDateTime.now();
//            LocalDateTime expiredTime = exchangeCode.getExpiredTime();
//            if (now.isAfter(expiredTime)){
//                throw new BizIllegalException("兑换码已过期");
//            }
//
//            Long userId = UserContext.getUser();
//            //查询优惠券信息
//            Coupon coupon = couponMapper.selectById(exchangeCode.getExchangeTargetId());
//            if (coupon == null){
//                throw new BizIllegalException("优惠券不存在");
//            }
//            //校验并生成用户券
//            checkAndCreateUserCoupon(userId,coupon,serialNum);
//
//        }catch (Exception e){
//            //将兑换码状态重置
//            exchangeCodeService.updateExchangeCodeMark(serialNum,false);
//            throw e;
//        }
//
//    }
//
//    @Transactional
//    public void checkAndCreateUserCoupon(Long userId, Coupon coupon, Long serialNum) {
//        //Long类型 -128-127 之间是同一个对象 超过该区间是不同的对象
//        //Long。toString 方法底层是new String，所以还是不同的对象
//        //Long.toString.intern intern方法是强制从常量池中取字符串
////        synchronized (userId.toString().intern()){
//            //获取当前用户 对该优惠券 已领数量 user_coupon 条件userId couponId
//            Integer count = this.lambdaQuery()
//                    .eq(UserCoupon::getUserId, userId)
//                    .eq(UserCoupon::getCouponId, coupon.getId())
//                    .count();
//            if (count != null && count>=coupon.getUserLimit()){
//                throw new BadRequestException("已达到领取上限");
//            }
//            //优惠券的已发放数量+1
////        coupon.setIssueNum(coupon.getIssueNum() + 1);
////        couponMapper.updateById(coupon);
//            couponMapper.incrIssueNum(coupon.getId());//采用这种方式 后期考虑并发控制 后期仍需修改
//
//            //生成用户券
//            saveUserCoupon(userId,coupon);
//
//            //更新兑换码状态
//            if (serialNum != null){
//                //修改兑换码状态
//                exchangeCodeService.lambdaUpdate()
//                        .set(ExchangeCode::getStatus, ExchangeCodeStatus.USED)
//                        .set(ExchangeCode::getUserId,userId)
//                        .eq(ExchangeCode::getId,serialNum)
//                        .update();
//            }
////        }
//    }
//
//    /**
//     * @description: 保存优惠券
//     * @params: [userId, coupon]
//     * @return:
//     * @author: ajie
//     * @date: 2024/5/24 16:05
//     */
//    private void saveUserCoupon(Long userId, Coupon coupon) {
//        UserCoupon userCoupon = new UserCoupon();
//        userCoupon.setUserId(userId);
//        userCoupon.setCouponId(coupon.getId());
//        LocalDateTime termBeginTime = coupon.getTermBeginTime();//优惠券使用 开始时间
//        LocalDateTime termEndTime = coupon.getTermEndTime();//优惠券使用 截止时间
//        if (termBeginTime == null && termEndTime == null){
//            termBeginTime = LocalDateTime.now();
//            termEndTime = termBeginTime.plusDays(coupon.getTermDays());
//        }
//        userCoupon.setTermBeginTime(termBeginTime);
//        userCoupon.setTermEndTime(termEndTime);
//        this.save(userCoupon);
//    }
//}
